import route from '@/router/index'

export function drawGalaxy (articleTypeList) {
  // canvas主画布
  let canvas = document.getElementById('galaxy')
  let context = canvas.getContext('2d')
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  // 主画布长宽高
  let canvasValue = {
    width: canvas.width,
    height: canvas.height,
    hypotenuse: Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height)
  }
  const fixedStarR = 45
  const num = articleTypeList.length
  let starArr = []
  let fixedStarArr = []
  let fixedStarLocArr = []

  // 颜色池
  const colors = [[255, 255, 255], [255, 0, 0], [255, 165, 0], [255, 255, 0],
    [0, 255, 0], [0, 127, 255], [0, 0, 255], [139, 0, 255]]

  // 小星星属性
  let Star = function (starX, starY, starZ, fixedStar) {
    this.starX = starX
    this.starY = starY
    this.starZ = starZ
    this.fixedStar = fixedStar
    this.starR = 10
  }
  Star.prototype.draw = function () {
    context.fillStyle = this.color
    const x = this.fixedStar.fixedStarX + this.starX
    const y = this.fixedStar.fixedStarY + this.starY
    const gradient2 = context.createRadialGradient(x, y, 0, x, y, 5)
    gradient2.addColorStop(0.05, getColor(this.fixedStar.fixedStarColor, '60%'))
    gradient2.addColorStop(0.2, getColor(this.fixedStar.fixedStarColor, '25%'))
    gradient2.addColorStop(0.35, getColor(this.fixedStar.fixedStarColor, '5%'))
    gradient2.addColorStop(1, getColor(this.fixedStar.fixedStarColor, '0%'))
    context.fillStyle = gradient2
    context.beginPath()
    let fl = 450
    let scale = fl / (fl - this.starZ)
    context.arc(x, y, this.starR * scale, 0, Math.PI * 2)
    context.fill()
    context.restore()
  }
  // 恒星属性
  let FixedStar = function (x, y, color, text) {
    this.fixedStarX = x
    this.fixedStarY = y
    this.fixedStarColor = color
    this.text = text
    this.fixedStarR = fixedStarR
    this.distance = (canvasValue.hypotenuse - (4 + 2 * num) * fixedStarR) / (num + 1)
  }
  FixedStar.prototype = {
    layerBallNum: 360 / 20,
    layerIntervalUp: 360 / 20,
    draw: function () {
      for (let i = 0; i < this.layerIntervalUp; i++) {
        let up = i < this.layerIntervalUp / 2 ? 1 : -1
        for (let j = 0; j < this.layerBallNum; j++) {
          let radius = Math.sqrt(Math.pow(this.fixedStarR, 2) - Math.pow(this.fixedStarR * Math.cos(i * Math.PI * 2 / this.layerBallNum), 2))
          let angle = 2 * Math.PI / this.layerBallNum * j
          let star = new Star(radius * Math.cos(angle), radius * Math.sin(angle), up * Math.sqrt(Math.pow(this.fixedStarR, 2) - Math.pow(radius, 2)), this)
          starArr.push(star)
        }
      }
    },
    fillText: function () {
      let text = this.text
      context.font = '20px Georgia'
      const maxWidth = this.fixedStarR * 1.6
      let width = context.measureText(text).width
      width = width > maxWidth ? maxWidth : width
      context.fillStyle = getOppositeColor(this.fixedStarColor, 1)
      context.fillText(text, this.fixedStarX - width / 2, this.fixedStarY + 6, maxWidth)
    }
  }

  let Meteor = function (meteorX, meteorY, meteorR) {
    this.meteorX = meteorX
    this.meteorY = meteorY
    this.meteorR = meteorR
    this.len = 10
    this.preX = 0
    this.preY = 0
    this.alpha = 0
  }
  Meteor.prototype = {
    move: function (comingNum) {
      let fixedStar = fixedStarArr[comingNum - 1] || new FixedStar(0, 0, 'white', '')
      if (!fixedStar.exist) {
        this.oval(comingNum, fixedStar)
      } else if (fixedStar.exist === 1) {
        this.arc(comingNum, fixedStar)
      }
    },
    oval: function (comingNum, fixedStar) {
      let _this = this
      let totalTime = 150
      for (let per = 1; per <= totalTime; per++) {
        setTimeout(function () {
          if (per / totalTime === 0.5) {
            if (comingNum <= num + 1) {
              drawStar(comingNum - 1, comingNum)
            }
          }
          sleep(1)
          _this.calcOval(fixedStar, per / totalTime, comingNum)
          _this.drawPentagram(per / totalTime, comingNum)
        }, 1)
      }
      fixedStar.exist = 1
      if (comingNum <= num) {
        this.move(comingNum)
      }
    },
    arc: function (comingNum, fixedStar) {
      let _this = this
      let totalTime = 100
      for (let per = 1; per <= totalTime; per++) {
        setTimeout(function () {
          sleep(1)
          _this.calcArc(fixedStar, per / totalTime, comingNum)
          _this.drawPentagram(1, comingNum)
        }, 1)
      }
      fixedStar.exist = 2
      if (comingNum <= num) {
        this.move(comingNum + 1)
      }
    },
    calcOval: function (fixedStar, per, comingNum) {
      let distanceMin = (2 * fixedStar.fixedStarR + fixedStar.distance) * (comingNum - 1)
      let distanceMax = distanceMin + 4 * fixedStar.fixedStarR + fixedStar.distance
      let xMin = distanceMin * canvasValue.width / canvasValue.hypotenuse
      let xMax = distanceMax * canvasValue.width / canvasValue.hypotenuse
      let yMin = distanceMin * canvasValue.height / canvasValue.hypotenuse
      let yMax = distanceMax * canvasValue.height / canvasValue.hypotenuse
      let a = xMax - xMin
      let b = yMax - yMin
      this.preX = this.meteorX
      this.preY = this.meteorY
      this.meteorX = xMin + (xMax - xMin) * per
      this.meteorY = yMax - Math.sqrt(b * b * (a * a - (this.meteorX - xMin) * (this.meteorX - xMin)) / (a * a))
      // this.alpha = 0
    },
    calcArc: function (fixedStar, per, comingNum) {
      let distanceMin = (2 * fixedStar.fixedStarR + fixedStar.distance) * comingNum
      let distanceMdd = distanceMin + fixedStar.fixedStarR
      let xMdd = distanceMdd * canvasValue.width / canvasValue.hypotenuse
      let yMdd = distanceMdd * canvasValue.height / canvasValue.hypotenuse

      let o = Math.acos(canvasValue.width / canvasValue.hypotenuse)
      let tempO = o + Math.PI * per
      this.preX = this.meteorX
      this.preY = this.meteorY
      this.meteorX = xMdd + Math.cos(tempO) * fixedStar.fixedStarR
      this.meteorY = yMdd + Math.sin(tempO) * fixedStar.fixedStarR
      this.alpha = per * 360 + 54
    },
    drawArc: function (per, comingNum) {
      // context.clearRect(this.preX - this.meteorR * 1.5, this.preY - this.meteorR * 1.5, 3 * this.meteorR, 3 * this.meteorR)
      context.fillStyle = getMeteorColor(colors[comingNum - 1], colors[comingNum] || 'white', per)
      context.beginPath()
      context.arc(this.meteorX, this.meteorY, this.meteorR, 0, 2 * Math.PI)
      context.closePath()
      context.fill()
    },
    drawPentagram: function (per, comingNum) {
      context.clearRect(this.preX - this.len * 1.2, this.preY - this.len * 1.2, 2.4 * this.len, 2.4 * this.len)
      context.beginPath()
      for (let i = 0; i < 5; i++) {
        context.lineTo(Math.cos((this.alpha + 18 + i * 72) / 180 * Math.PI) * this.len + this.meteorX, -Math.sin((this.alpha + 18 + i * 72) / 180 * Math.PI) * this.len + this.meteorY)
        context.lineTo(Math.cos((this.alpha + 54 + i * 72) / 180 * Math.PI) * this.len * 0.4 + this.meteorX, -Math.sin((this.alpha + 54 + i * 72) / 180 * Math.PI) * this.len * 0.4 + this.meteorY)
      }
      context.closePath()
      context.fillStyle = getMeteorColor(colors[comingNum - 1], colors[comingNum] || 'white', per)
      context.fill()
      context.stroke()
    }
  }

  function Animation () {
    // resetBackground()
    drawFixedStar()
    drawMeteor()
    watching()
  }

  let thisWatching
  const watching = function () {
    if (thisWatching) {
      starMove()
    }
    window.requestAnimationFrame(watching)
  }

  const starMove = function () {
    rotateX()
    rotateY()
    rotateZ()
    context.clearRect(0, 0, canvasValue.width, canvasValue.height)
    drawStar()
  }

  canvas.onmousedown = function (e) {
    mouseDown(e)
  }
  canvas.onmousemove = function (e) {
    mouseMove(e)
  }

  function drawMeteor () {
    new Meteor(0, 0, 6).move(1)
  }

  function drawStar (begin, end) {
    begin = begin ? begin - 1 : 0
    end = end ? end - 1 : fixedStarArr.length
    for (let i = starArr.length / num * begin; i < starArr.length / num * end; i++) {
      if (starArr[i].fixedStar.exist === 2) {
        starArr[i].draw()
      }
    }
    for (let i = begin; i < end; i++) {
      if (fixedStarArr[i].exist) {
        fixedStarArr[i].fillText()
      }
    }
    if (end === num) {
      thisWatching = true
    }
  }
  function drawFixedStar () {
    const distance = (canvasValue.hypotenuse - (4 + 2 * num) * fixedStarR) / (num + 1)
    for (let i = 1; i <= num; i++) {
      let temp = ((2 * fixedStarR + distance) * i + fixedStarR) / canvasValue.hypotenuse
      let fixedStarLoc = {
        x: temp * canvasValue.width,
        y: temp * canvasValue.height
      }
      let fixedStar = new FixedStar(fixedStarLoc.x, fixedStarLoc.y, colors[i], articleTypeList[i - 1].title)
      fixedStar.draw()
      fixedStarArr.push(fixedStar)
      fixedStarLocArr[i - 1] = fixedStarLoc
    }
  }

  // 重置主画布背景颜色
  // function resetBackground () {
  //   context.globalAlpha = 0.8
  //   context.fillStyle = 'hsla(217, 64%, 6%, 1)'
  //   context.fillRect(0, 0, canvasValue.width, canvasValue.height)
  // }

  // 小球旋转属性
  let initAngle = -0.1
  let angleX = new Array(num).fill(initAngle)
  let angleY = new Array(num).fill(initAngle)

  function rotateX () {
    let everyNum = starArr.length / num
    for (let fixStar = 0; fixStar < num; fixStar++) {
      let cos = Math.cos(angleX[fixStar])
      let sin = Math.sin(angleX[fixStar])
      for (let i = fixStar * everyNum; i < (fixStar + 1) * everyNum; i++) {
        let y1 = starArr[i].starY * cos - starArr[i].starZ * sin
        let z1 = starArr[i].starZ * cos + starArr[i].starY * sin
        starArr[i].starY = y1
        starArr[i].starZ = z1
      }
    }
  }

  function rotateY () {
    let everyNum = starArr.length / num
    for (let fixStar = 0; fixStar < num; fixStar++) {
      let cos = Math.cos(angleY[fixStar])
      let sin = Math.sin(angleY[fixStar])
      for (let i = fixStar * everyNum; i < (fixStar + 1) * everyNum; i++) {
        let x1 = starArr[i].starX * cos - starArr[i].starZ * sin
        let z1 = starArr[i].starZ * cos + starArr[i].starX * sin
        starArr[i].starX = x1
        starArr[i].starZ = z1
      }
    }
  }

  function rotateZ () {
    let everyNum = starArr.length / num
    for (let fixStar = 0; fixStar < num; fixStar++) {
      let cos = Math.cos(angleY[fixStar])
      let sin = Math.sin(angleY[fixStar])
      for (let i = fixStar * everyNum; i < (fixStar + 1) * everyNum; i++) {
        let x1 = starArr[i].starX * cos - starArr[i].starY * sin
        let y1 = starArr[i].starY * cos + starArr[i].starX * sin
        starArr[i].starX = x1
        starArr[i].starY = y1
      }
    }
  }

  function mouseDown (event) {
    let x = event.clientX
    let y = event.clientY
    for (let i = 0; i < num; i++) {
      let width = fixedStarLocArr[i].x
      let height = fixedStarLocArr[i].y
      if ((x - width) * (x - width) + (y - height) * (y - height) < fixedStarR * fixedStarR) {
        console.log('您选择了' + articleTypeList[i].title)
        route.push({path: '/article/list?typeId=' + articleTypeList[i].id})
      }
    }
  }

  function mouseMove (event) {
    for (let i = 0; i < num; i++) {
      let x = event.clientX - canvas.offsetLeft - fixedStarArr[i].fixedStarX
      let y = event.clientY - canvas.offsetTop - fixedStarArr[i].fixedStarY
      angleY[i] = -x * 0.0005
      angleX[i] = -y * 0.0005
    }
  }

  Animation()
}
function getColor (color, a) {
  return 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + a + ')'
}
function getOppositeColor (color, a) {
  let tempColor = [255 - color[0], 255 - color[1], 255 - color[2]]
  return getColor(tempColor, a)
}
function getMeteorColor (colorFrom, colorTo, per) {
  let rgb = []
  rgb[0] = colorFrom[0] + (colorTo[0] - colorFrom[0]) * per
  rgb[1] = colorFrom[1] + (colorTo[1] - colorFrom[1]) * per
  rgb[2] = colorFrom[2] + (colorTo[2] - colorFrom[2]) * per
  return getColor(rgb, 1)
}
// 同步睡眠
function sleep (mills) {
  let now = new Date().getTime()
  while (true) {
    if (new Date().getTime() > now + mills) {
      return
    }
  }
}
